﻿using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using CodeC.Utilities;
using CodeC.Models;
using System.CodeDom.Compiler;
using CodeC.Interfaces;

namespace CodeC.Test
{
   /// <summary>
   /// Unit test cases are not completed fully
   /// </summary>
    [TestClass]
    public class CodeCTest
    {
        public CodeCTest()
        {
            
        }

        [TestMethod]
        public void CodeCEnginePositiveTest()
        {
            #region Code

            string classCode = "using System;" + Environment.NewLine +
                                "using System.Collections.Generic;" + Environment.NewLine +
                          "namespace HelloWorld" + Environment.NewLine +
                          "{" + Environment.NewLine +
                          "	/// <summary>" + Environment.NewLine +
                          "	/// Summary description for Class1." + Environment.NewLine +
                          "	/// </summary>" + Environment.NewLine +
                          "	class HelloWorldClass" + Environment.NewLine +
                          "	{" + Environment.NewLine +
                          "		static void Main(string[] args)" + Environment.NewLine +
                          "		{" + Environment.NewLine +
                         "      Console.WriteLine(\"Hi Artha\");" + Environment.NewLine +
                        "       int i = 10;" + Environment.NewLine +
                        "       for (var j = 0; j < i; j++)" + Environment.NewLine +
                            "       Console.WriteLine(\"Artha:\" + j);" + Environment.NewLine +

                        "       IList<string> lst = new List<string> { \"one\", \"two\", \"three\" };" + Environment.NewLine +

                        "       foreach (var item in lst)" + Environment.NewLine +
                        "           Console.WriteLine(item);" + Environment.NewLine +

                          "		}" + Environment.NewLine +
                          "	}" + Environment.NewLine +
                          "}";
            #endregion

            CodeCEngine codeCEngine = new CodeCEngine();
            var output = codeCEngine.CompileCode(classCode, null);

            Assert.IsNotNull(output);
            Assert.IsNull(output.Errors);
            Assert.IsNotNull(output.Result);

        }

        [TestMethod]
        public void CodeCEngineNegativeTest()
        {
            #region Code

            string classCode = "using System;" + Environment.NewLine +
                                "using System.Collections.Generic;" + Environment.NewLine +
                          "namespace HelloWorld" + Environment.NewLine +
                          "{" + Environment.NewLine +
                          "	/// <summary>" + Environment.NewLine +
                          "	/// Summary description for Class1." + Environment.NewLine +
                          "	/// </summary>" + Environment.NewLine +
                          "	class HelloWorldClass" + Environment.NewLine +
                          "	{" + Environment.NewLine +
                          "		static void Main(string[] args)" + Environment.NewLine +
                          "		{" + Environment.NewLine +
                         "      Console.WriteLine(\"Hi Artha\");" + Environment.NewLine +
                        "       int i1 = 10;" + Environment.NewLine +
                        "       for (var j = 0; j < i; j++)" + Environment.NewLine +
                            "       Console.WriteLine(\"Artha:\" + j);" + Environment.NewLine +

                        "       IList<string> lst = new List<string> { \"one\", \"two\", \"three\" };" + Environment.NewLine +

                        "       foreach (var item in lst)" + Environment.NewLine +
                        "           Console.WriteLine(item);" + Environment.NewLine +

                          "		}" + Environment.NewLine +
                          "	}" + Environment.NewLine +
                          "}";
            #endregion

            CodeCEngine codeCEngine = new CodeCEngine();
            var output = codeCEngine.CompileCode(classCode, null);

            Assert.IsNotNull(output);
            Assert.IsNotNull(output.Errors);
            foreach (CompilerError compilerError in output.Errors)
                Assert.AreEqual(14, compilerError.Line);// Error occur in line 14.

            Assert.IsNull(output.Result);

        }

        [TestMethod]
        public void CodeGeneratorTest()
        {
            #region Code

            string classCode =
                         "      Console.WriteLine(\"Hi Artha\");";


            #endregion


            CodeCModel model = new CodeCModel { MainCode = classCode };

            CodeC.Utilities.CodeGenerator codeGenerator = new Utilities.CodeGenerator();
            classCode = codeGenerator.GenerateClassString(SetCodeCModel(model));

            CodeCEngine codeCEngine = new CodeCEngine();
            var output = codeCEngine.CompileCode(classCode, model.ListOfReferences);

            Assert.IsNotNull(output);
            Assert.IsNull(output.Errors);
            Assert.IsNotNull(output.Result);

        }

        [TestMethod]
        public void CodeGeneratorWithMethodsTest()
        {
            #region Code

            string mainCode =
                         "     DisplayName();";

            string methodCode = " public void DisplayName()" + Environment.NewLine +
                                "{" + Environment.NewLine +
                                "Console.WriteLine(\"Hi Artha\");" + Environment.NewLine +
                                "}";

            #endregion


            CodeCModel model = new CodeCModel { MainCode = mainCode, ClassMethodsCode = methodCode };

            CodeC.Utilities.CodeGenerator codeGenerator = new Utilities.CodeGenerator();
            mainCode = codeGenerator.GenerateClassString(SetCodeCModel(model));

            CodeCEngine codeCEngine = new CodeCEngine();
            var output = codeCEngine.CompileCode(mainCode, model.ListOfReferences);

            Assert.IsNotNull(output);
            Assert.IsNull(output.Errors);
            Assert.IsNotNull(output.Result);

        }

        [TestMethod]
        public void CodeGeneratorWithClassMethodsTest()
        {
            #region Code

            string mainCode =
                         "DisplayName();";

            string methodCode = "public void DisplayName()" + Environment.NewLine +
                                "{" + Environment.NewLine +
                                "var codeTest = new CodeTest();  " + Environment.NewLine +
                                "}";

            string classCode = "public class CodeTest" + Environment.NewLine +
                                "{" + Environment.NewLine +
                                    "public CodeTest()" + Environment.NewLine +
                                    "{" + Environment.NewLine +
                                        "Console.WriteLine(\"Hi Artha\");" + Environment.NewLine +
                                    "}" + Environment.NewLine +
                                "}";

            #endregion


            CodeCModel model = new CodeCModel { MainCode = mainCode, ClassMethodsCode = classCode + methodCode };

            CodeC.Utilities.CodeGenerator codeGenerator = new Utilities.CodeGenerator();
            mainCode = codeGenerator.GenerateClassString(SetCodeCModel(model));

            CodeCEngine codeCEngine = new CodeCEngine();
            var output = codeCEngine.CompileCode(mainCode, model.ListOfReferences);

            Assert.IsNotNull(output);
            Assert.IsNull(output.Errors);
            Assert.IsNotNull(output.Result);

        }

        [TestMethod]
        public void CodeGeneratorWithClassMethodsErrorInMainCodeTest()
        {
            #region Code

            string mainCode =
                         "DisplayName1();";

            string methodCode = "public void DisplayName()" + Environment.NewLine +
                                "{" + Environment.NewLine +
                                "var codeTest = new CodeTest();  " + Environment.NewLine +
                                "}";

            string classCode = "public class CodeTest" + Environment.NewLine +
                                "{" + Environment.NewLine +
                                    "public CodeTest()" + Environment.NewLine +
                                    "{" + Environment.NewLine +
                                        "Console.WriteLine(\"Hi Artha\");" + Environment.NewLine +
                                    "}" + Environment.NewLine +
                                "}";

            #endregion


            CodeCModel model = new CodeCModel { MainCode = mainCode, ClassMethodsCode = classCode + methodCode };

            CodeC.Utilities.CodeGenerator codeGenerator = new Utilities.CodeGenerator();
            mainCode = codeGenerator.GenerateClassString(SetCodeCModel(model));

            CodeCEngine codeCEngine = new CodeCEngine();
            var output = codeCEngine.CompileCode(mainCode, model.ListOfReferences);

            Assert.IsNotNull(output);
            Assert.IsNotNull(output.Errors);
            foreach (CompilerError compilerError in output.Errors)
                Assert.AreEqual(127, compilerError.Line);// Error occur in line 2.

            Assert.IsNull(output.Result);

        }

        [TestMethod]
        public void CodeGeneratorWithClassMethodsErrorInMethodCodeTest()
        {
            #region Code

            string mainCode =
                         "DisplayName();";

            string methodCode = "public void DisplayName()" + Environment.NewLine +
                                "{" + Environment.NewLine +
                                "var codeTest = new CodeTest1();  " + Environment.NewLine +
                                "}";

            string classCode = "public class CodeTest" + Environment.NewLine +
                                "{" + Environment.NewLine +
                                    "public CodeTest()" + Environment.NewLine +
                                    "{" + Environment.NewLine +
                                        "Console.WriteLine(\"Hi Artha\");" + Environment.NewLine +
                                    "}" + Environment.NewLine +
                                "}";

            #endregion


            CodeCModel model = new CodeCModel { MainCode = mainCode, ClassMethodsCode = classCode + methodCode };

            CodeC.Utilities.CodeGenerator codeGenerator = new Utilities.CodeGenerator();
            mainCode = codeGenerator.GenerateClassString(SetCodeCModel(model));

            CodeCEngine codeCEngine = new CodeCEngine();
            var output = codeCEngine.CompileCode(mainCode, model.ListOfReferences);

            Assert.IsNotNull(output);
            Assert.IsNotNull(output.Errors);
            foreach (CompilerError compilerError in output.Errors)
                Assert.AreEqual(137, compilerError.Line);// Error occur in line 2.

            Assert.IsNull(output.Result);

        }

        private CodeCModel SetCodeCModel(CodeCModel codeCModel)
        {
            #region Default List Of References
            codeCModel.ListOfReferences = new List<string>{
                        "System.dll",
                        "System.Core.dll",
                        "System.Xml.Linq.dll",
                        "System.Data.DataSetExtensions.dll",
                        "Microsoft.CSharp.dll",
                        "System.Data.dll",
                        "System.Xml.dll",
                        "mscorlib.dll"};
            #endregion

            #region Default List Of Namespaces
            codeCModel.ListOfNamespaces = new List<string>{
                        "System.Text.RegularExpressions",
                        "System.CodeDom",
                        "System.ComponentModel",
                        "System.ComponentModel.Design",
                        "System.ComponentModel.Design.Serialization",
                        "System.Diagnostics",
                        "System.CodeDom.Compiler",
                        "System.Configuration",
                        "System.IO.Compression",
                        "System.IO",
                        "System.Runtime.InteropServices",
                        "System.Runtime.Versioning",
                        "System.Threading",
                        "System.Collections.Concurrent",
                        "System.Media",
                        "System.Security.AccessControl",
                        "System.Collections.Generic",
                        "System",
                        "System.Collections.Specialized",
                        "System.Collections.ObjectModel",
                        "Microsoft.Win32",
                        "System.Runtime.InteropServices.ComTypes",
                        "Microsoft.Win32.SafeHandles",
                        "Microsoft.CSharp",
                        "Microsoft.VisualBasic",
                        "System.Security.Permissions",
                        "System.Security.Cryptography",
                        "System.Security.Cryptography.X509Certificates",
                        "System.Security.Authentication.ExtendedProtection",
                        "System.Security.Authentication.ExtendedProtection.Configuration",
                        "System.Net",
                        "System.Net.Sockets",
                        "System.Net.Security",
                        "System.Net.Cache",
                        "System.Security.Authentication",
                        "System.Net.NetworkInformation",
                        "System.Net.Configuration",
                        "System.Net.Mail",
                        "System.Net.Mime",
                        "System.Configuration.Internal",
                        "System.Timers",
                        "System.Web",
                        "System.Diagnostics.CodeAnalysis",
                        "System.IO.Ports",
                        "System.Diagnostics.Eventing",
                        "System.Management.Instrumentation",
                        "System.Diagnostics.Eventing.Reader",
                        "System.Linq.Expressions",
                        "System.Linq",
                        "System.Runtime.CompilerServices",
                        "System.Linq.Parallel",
                        "System.Security",
                        "System.Security.Cryptography.Xml",
                        "System.Dynamic",
                        "System.Dynamic.Utils",
                        "System.Linq.Expressions.Compiler",
                        "System.Diagnostics.PerformanceData",
                        "System.IO.Pipes",
                        "System.Threading.Tasks",
                        "System.IO.MemoryMappedFiles",
                        "System.Xml.Linq",
                        "System.Xml.XPath",
                        "System.Xml.Schema",
                        "MS.Internal.Xml.Linq.ComponentModel",
                        "System.Data.DataSetExtensions",
                        "System.Data",
                        "Microsoft.CSharp.RuntimeBinder",
                        "Microsoft.CSharp.RuntimeBinder.Semantics",
                        "Microsoft.CSharp.RuntimeBinder.Errors",
                        "Microsoft.CSharp.RuntimeBinder.Syntax",
                        "Microsoft.SqlServer.Server",
                        "System.Data.Common",
                        "System.Data.ProviderBase",
                        "System.Data.Odbc",
                        "System.Data.OleDb",
                        "System.Data.Sql",
                        "System.Data.SqlClient",
                        "System.Data.SqlTypes",
                        "System.Xml",
                        "MS.Internal.Xml.Cache",
                        "System.Xml.Resolvers",
                        "MS.Internal.Xml.XPath",
                        "System.Xml.Xsl",
                        "System.Xml.Serialization",
                        "System.Xml.Serialization.Advanced",
                        "System.Xml.Serialization.Configuration",
                        "System.Runtime.Serialization",
                        "System.Collections",
                        "System.Text",
                        "System.Runtime.Hosting",
                        "System.Security.Policy",
                        "System.Deployment.Internal",
                        "System.Runtime.ConstrainedExecution",
                        "System.Reflection",
                        "System.StubHelpers",
                        "System.Runtime.Remoting",
                        "System.Deployment.Internal.Isolation.Manifest",
                        "System.Deployment.Internal.Isolation",
                        "System.Diagnostics.Contracts",
                        "System.Diagnostics.Contracts.Internal",
                        "System.Diagnostics.SymbolStore",
                        "Microsoft.Runtime.Hosting",
                        "System.Runtime.ExceptionServices",
                        "System.Globalization",
                        "System.Resources",
                        "System.Security.Util",
                        "System.Security.Principal",
                        "System.Runtime.InteropServices.Expando",
                        "System.Runtime",
                        "System.Runtime.Remoting.Activation",
                        "System.Runtime.Remoting.Contexts",
                        "System.Runtime.Remoting.Messaging",
                        "System.Runtime.Remoting.Channels",
                        "System.Runtime.Remoting.Lifetime",
                        "System.Runtime.Remoting.Services",
                        "System.Runtime.Serialization.Formatters",
                        "System.Runtime.Remoting.Proxies",
                        "System.Runtime.Remoting.Metadata",
                        "System.Runtime.Remoting.Metadata.W3cXsd2001",
                        "System.IO.IsolatedStorage",
                        "System.Runtime.Serialization.Formatters.Binary",
                        "System.Reflection.Emit",
                        "System.Reflection.Cache",
                        "System.Configuration.Assemblies",
                        "System.Runtime.InteropServices.TCEAdapterGen"
                        };
            #endregion

            return codeCModel;
        }

        [TestMethod]
        public void CodeGeneratorWithClassMethodsErrorInClassCodeCodeTest()
        {
            #region Code

            string mainCode =
                         "DisplayName();";

            string methodCode = "public void DisplayName()" + Environment.NewLine +
                                "{" + Environment.NewLine +
                                "var codeTest = new CodeTest();  " + Environment.NewLine +
                                "}";

            string classCode = "public class CodeTest" + Environment.NewLine +
                                "{" + Environment.NewLine +
                                    "public CodeTest1()" + Environment.NewLine +
                                    "{" + Environment.NewLine +
                                        "Console.WriteLine(\"Hi Artha\");" + Environment.NewLine +
                                    "}" + Environment.NewLine +
                                "}";

            #endregion


            CodeCModel model = new CodeCModel { MainCode = mainCode, ClassMethodsCode = classCode + methodCode };

            CodeC.Utilities.CodeGenerator codeGenerator = new Utilities.CodeGenerator();
            mainCode = codeGenerator.GenerateClassString(SetCodeCModel(model));

            CodeCEngine codeCEngine = new CodeCEngine();
            var output = codeCEngine.CompileCode(mainCode, model.ListOfReferences);

            Assert.IsNotNull(output);
            Assert.IsNotNull(output.Errors);
            foreach (CompilerError compilerError in output.Errors)
                Assert.AreEqual(131, compilerError.Line);// Error occur in line 2.

            Assert.IsNull(output.Result);

        }

        [TestMethod]
        public void CodeCHelpterTest()
        {
            #region Code

            string mainCode =
                         "DisplayName();";

            string methodCode = "public void DisplayName()" + Environment.NewLine +
                                "{" + Environment.NewLine +
                                "var codeTest = new CodeTest();  " + Environment.NewLine +
                                "}";

            string classCode = "public class CodeTest" + Environment.NewLine +
                                "{" + Environment.NewLine +
                                    "public CodeTest()" + Environment.NewLine +
                                    "{" + Environment.NewLine +
                                        "Console.WriteLine(\"Hi Artha\");" + Environment.NewLine +
                                    "}" + Environment.NewLine +
                                "}";

            #endregion


            CodeCModel model = new CodeCModel { MainCode = mainCode, ClassMethodsCode = classCode + methodCode };

            var codeCHelper = new CodeCHelper(new FileOperations(), new XMLFileOperations(new FileOperations())) { _codeCEngine = new CodeCEngine(), _createClassCode = new CodeC.Utilities.CodeGenerator() };
            var output = codeCHelper.Run(SetCodeCModel(model));

            Assert.IsNotNull(output);
            Assert.IsNull(output.Errors);
            Assert.IsNotNull(output.Result);

        }


        [TestMethod]
        public void FileOperationWriteFileTest()
        {
            FileOperations fileOperations = new FileOperations();
            string content = "Sample content test";
            string filename = "one.CodeC";

            var str = fileOperations.Write(filename, content);
            Assert.IsNotNull(str);
            str = fileOperations.Read(str);
            Assert.AreEqual(str, content);

        }


        [TestMethod]
        public void ModelSaveTest()
        {
            #region Code

            string mainCode =
                         "DisplayName();";

            string methodCode = "public void DisplayName()" + Environment.NewLine +
                                "{" + Environment.NewLine +
                                "var codeTest = new CodeTest();  " + Environment.NewLine +
                                "}";

            string classCode = "public class CodeTest" + Environment.NewLine +
                                "{" + Environment.NewLine +
                                    "public CodeTest()" + Environment.NewLine +
                                    "{" + Environment.NewLine +
                                        "Console.WriteLine(\"Hi Artha\");" + Environment.NewLine +
                                    "}" + Environment.NewLine +
                                "}";

            #endregion


            CodeCModel model = new CodeCModel { MainCode = mainCode, ClassMethodsCode = classCode + methodCode };

            CodeCHelper helper = new CodeCHelper(new FileOperations(), new XMLFileOperations(new FileOperations()));
            var t = helper.SaveCode(model, new CodeCFileModel { ID = 0, Name = "First" });
            Assert.IsTrue(t.ID > 0);



        }

        [TestMethod]
        public void XMLFileOperationConstructorTest()
        {
            XMLFileOperations xmlop = new XMLFileOperations(new FileOperations());
            xmlop.Write(new CodeCFileModel { ID = 0, Name = "Test Name", File = "TestName.codec" });
            xmlop.Write(new CodeCFileModel { ID = 0, Name = "Test Name", File = "TestName.codec" });
            var lst = xmlop.Read();
            Assert.AreEqual(lst.Count, 2);

        }
    }
}
